#ifndef EXPRESSIONCPP
#define EXPRESSIONCPP

#include"expression.hpp"
#include"interpreter.hpp"

std::string literal::toString(){
	return value;
}

void literal::output(){
	std::cout<<value;
}

literal::literal(std::string type,std::string value){
	this->type=type;
	this->value=value;
	this->etype=LITERAL;
}

var* literal::getValue(interpreter* i){
	if(this->type=="IDENTIFIER"){
		var* tmp=i->find(this->value);
		if(tmp==nullptr){
			std::cout<<"variable not found\n";
			return new nil();
		}
		return tmp;
	}
	if(this->type=="STRING")return new string(this->value,true);
	if(this->type=="NUMBER")return new number(atof(this->value.c_str()),true);
	if(this->type=="BOOL")return new boolean(this->value=="true"?true:false,true);
	return new nil();
}

std::string unary::toString(){
	return "("+oper.getLexeme()+" "+right->toString()+")";
}

void unary::output(){
	std::cout<<"("<<oper.getLexeme()<<" ";
	right->output();std::cout<<")";
}

unary::unary(token oper,expression* right){
	this->oper=oper;
	this->right=right;
	this->etype=UNARY;
}

var* unary::getValue(interpreter* i){
	var* rvar=this->right->getValue(i);
	var* tvar=nullptr;
	if(this->oper.getType()=="MINUS")
		tvar=Operator::getOper()->MINUS(rvar,oper.getLine());
	if(this->oper.getType()=="BANG")
		tvar=Operator::getOper()->BANG(rvar,oper.getLine());
	if(rvar->instant)DELETE(rvar);
	if(tvar==nullptr)return new nil();
	return tvar;
}

std::string binary::toString(){
	return "("+oper.getLexeme()+" "+left->toString()+" "+right->toString()+")";
}

void binary::output(){
	std::cout<<"("<<oper.getLexeme()<<" ";
	left->output();std::cout<<" ";
	right->output();std::cout<<")";
}

binary::binary(expression* left,token oper,expression* right){
	this->left=left;
	this->right=right;
	this->oper=oper;
	this->etype=BINARY;
}

var* binary::getValue(interpreter* i){
	var* lvar=this->left->getValue(i);
	var* rvar=this->right->getValue(i);
	var* tvar=nullptr;
	if(this->oper.getType()=="MINUS")
		tvar=Operator::getOper()->MINUS(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="PLUS")
		tvar=Operator::getOper()->PLUS(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="STAR")
		tvar=Operator::getOper()->STAR(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="BANG_EQUAL")
		tvar=Operator::getOper()->BANG_EQUAL(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="EQUAL_EQUAL")
		tvar=Operator::getOper()->EQUAL_EQUAL(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="GREATER_EQUAL")
		tvar=Operator::getOper()->GREATER_EQUAL(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="GREATER")
		tvar=Operator::getOper()->GREATER(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="LESS_EQUAL")
		tvar=Operator::getOper()->LESS_EQUAL(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="LESS")
		tvar=Operator::getOper()->LESS(lvar,rvar,oper.getLine());
	if(this->oper.getType()=="SLASH")
		tvar=Operator::getOper()->SLASH(lvar,rvar,oper.getLine());
	if(lvar->instant)DELETE(lvar);
	if(rvar->instant)DELETE(rvar);
	if(tvar==nullptr)return new nil();
	return tvar;
}

std::string group::toString(){
	return "(group "+gexp->toString()+")";
}

void group::output(){
	std::cout<<"(group ";gexp->output();std::cout<<")";
}

group::group(expression* gexp){
	this->gexp=gexp;
	this->etype=GROUP;
}

var* group::getValue(interpreter* i){
	return this->gexp->getValue(i);
}

#endif